#include "mat_tutorial.h"
#include "mat_game.h"
#include "mat_define.h"
#include "gen_game_state.h"
#include "mat_gamerule.h"
#include "mat_animation_mgr.h"
#include "mat_ui_popupanimator.h"
#include "mat_ui_msgbox.h"
#include "mat_gamerule.h"
#include "mat_level_manager.h"

#include "util/log.h"
#include "ui/ui_manager.h"
#include "application/game_application.h"
#include "application/game_rms.h"
#include "script/scripthelper.h"
#include "graphics/graphics_util.h"
#include "util/common_macros.h"		// macros
#include "util/mmgr.h"	


using namespace script;

MATTutorial::MATTutorial() : m_CurrentTutorial(-1),
							 m_CurrentStep(-1),
							 m_State(STATE_NONE),
							 m_CounterToNextState(0),
							 m_CurrentX(-1),
							 m_CurrentY(-1),
							 //m_DistToTravel(0),
							 m_StartDelay(3.0f),
							 m_pUIInstruction(NULL),
							 m_IsLoaded(false),
							 m_AnotherClickDelay(0)
{
	m_pUIInstruction = ui::UIManager::Instance().GetWidget("tutorialtext");
	if(m_pUIInstruction)
		m_pUIInstruction->SetTextA("");

	m_SpriteFinger.Create("finger");
	m_SpriteFingerSize = m_SpriteFinger.m_Size;
	m_SpriteFinger.m_Color = ColorfRGBA(0.75f,0.75f,0.75f,0.75f);

	m_SpriteArrow.Create("arrow");
	m_SpriteArrowSize = m_SpriteArrow.m_Size; 

	m_SpriteBlack.Create("black_bg");
	m_CounterArrow.SetLimit(0.9f);
	m_SpriteBlack.m_Size = math::Vec2(1.0f,1.0f);
	m_SpriteBlack.m_Color = ColorfRGBA(0.75f,0.75f,0.75f,0.75f);
}

MATTutorial::BoardInfo::BoardInfo()
{
	m_Content = MATGameRule::Instance().GetNewGemToSpawn();
}

MATTutorial::~MATTutorial()
{
	
	Clear();	
}

void		MATTutorial::Clear()
{
	for(int i = 0; i < (int)m_Tutorials.size(); i++)
	{
		TutorialData* pData = m_Tutorials[i];
		UTIL_SAFE_DELETE(pData);
	}
	m_Tutorials.resize(0);
	m_State = STATE_CLEARED;
	
}

MATTutorial::TutorialData::~TutorialData()
{
	for(int i = 0; i < (int)m_Moves.size(); i++)
	{
		UTIL_SAFE_DELETE(m_Moves[i]);
	}
	m_Moves.resize(0);

	for(int i = 0; i < (int)m_BoardStart.size(); i++)
	{
		UTIL_SAFE_DELETE(m_BoardStart[i]);
	}
	m_BoardStart.resize(0);
		
}

MATTutorial::TutorialMove::~TutorialMove()
{
	for(int i = 0; i < (int)m_Smalls.size(); i++)
	{
		UTIL_SAFE_DELETE(m_Smalls[i]);
	}
}

void		MATTutorial::Load()
{
	if(m_IsLoaded)
		return;

	m_IsLoaded = true;

	const std::string FileName = "infos/tutorials.lua";
	LuaPlus::LuaState*	pScript = ScriptHelper::CreateLuaState();
	{
		if (!ScriptHelper::DoFile(*pScript, FileName))
		{
			LuaPlus::LuaState::Destroy( pScript );
			return;
		} 	
		
		LuaPlus::LuaObject TutorialTable = pScript->GetGlobal("Tutorial");
		for(int j =0; j <TutorialTable.GetTableCount(); j++)
		{
			
			LuaPlus::LuaObject TutorialObj = TutorialTable.GetByIndex(j+1);
			TutorialData* pTutorialData = new TutorialData();
			m_Tutorials.push_back(pTutorialData);

			pTutorialData->m_ActivateLevel = ScriptHelper::GetTableInt(TutorialObj,"ActivateLevel");
			LuaPlus::LuaObject Table = TutorialObj.GetByName("Board");
			for(int i =0; i <Table.GetTableCount(); i++)
			{
				LuaPlus::LuaObject Obj = Table.GetByIndex(i+1);

				BoardInfo*	pBoardInfo = new BoardInfo();
				pBoardInfo->m_Content->m_Type  = ScriptHelper::GetTableInt(Obj,"Gem");
				pBoardInfo->m_X = ScriptHelper::GetTableInt(Obj,"X"); 			
				pBoardInfo->m_Y = ScriptHelper::GetTableInt(Obj,"Y"); 

				pTutorialData->m_BoardStart.push_back(pBoardInfo);			
			}
			
			

			
			LuaPlus::LuaObject MoveTable = TutorialObj.GetByName("Moves");			
			for(int i = 0; i < MoveTable.GetTableCount(); i++)
			{
				TutorialMove* pTutorialMove = new TutorialMove();
				pTutorialData->m_Moves.push_back(pTutorialMove);
				LuaPlus::LuaObject Obj = MoveTable.GetByIndex(i+1);

				pTutorialMove->m_Text1 = ScriptHelper::GetTableString(Obj,"Text1"); 
				pTutorialMove->m_Text2 = ScriptHelper::GetTableString(Obj,"Text2"); 

				LuaPlus::LuaObject SubObj = Obj.GetByName("MoveInfo");
				pTutorialMove->m_StartX = ScriptHelper::GetTableInt(SubObj,"StartX"); 	
				pTutorialMove->m_StartY = ScriptHelper::GetTableInt(SubObj,"StartY"); 	
				pTutorialMove->m_EndX = ScriptHelper::GetTableInt(SubObj,"EndX"); 	
				pTutorialMove->m_EndY = ScriptHelper::GetTableInt(SubObj,"EndY"); 	

				
				LuaPlus::LuaObject SubTable = Obj.GetByName("Smalls");
				for(int k =0; k <SubTable.GetTableCount(); k++)
				{
					LuaPlus::LuaObject SubObj2 = SubTable.GetByIndex(k+1);
					BoardInfo*	pBoardInfo = new BoardInfo();
					pBoardInfo->m_Content->m_Type  = ScriptHelper::GetTableInt(SubObj2,"Gem");
					pBoardInfo->m_X = ScriptHelper::GetTableInt(SubObj2,"X"); 			
					pBoardInfo->m_Y = ScriptHelper::GetTableInt(SubObj2,"Y"); 
					pTutorialMove->m_Smalls.push_back(pBoardInfo);
					m_CurrentStep = 0;
				}
			}
			m_CurrentTutorial = 0;
			
		}	// for(int j =0; j <TutorialTable.GetTableCount(); j++)
		
	}
	LuaPlus::LuaState::Destroy( pScript );


}

bool		MATTutorial::Start()
{
	m_StartDelay = 3.0f;
	//m_State = STATE_CLEARED;
	if(m_CurrentTutorial < 0)
		return false;

	if(m_CurrentTutorial >= (int)m_Tutorials.size())
		return false;

	TutorialData* pTutorialData =  m_Tutorials[m_CurrentTutorial];
	if(!pTutorialData)
		return false;


	if(pTutorialData->m_ActivateLevel == MATLevelManager::Instance().GetCurrentLevel())
	{

		for(int i =0; i < (int)pTutorialData->m_BoardStart.size(); i++)
		{
			MATTutorial::BoardInfo* pBoardInfo = pTutorialData->m_BoardStart[i];
			MATLogicBoard::Instance().SetContentAt( pBoardInfo->m_Y , pBoardInfo->m_X , pBoardInfo->m_Content );
		}
		m_CurrentStep = 0;
		m_State = STATE_NONE;
		MATGameRule::Instance().NextTurn();
		return true;
	}
	else if(pTutorialData->m_ActivateLevel > MATLevelManager::Instance().GetCurrentLevel())
	{
		m_State = STATE_WAIING_TOACTIVATE;
	}
	else
	{
		
		m_State = STATE_WAIING_TOACTIVATE;
		m_CurrentTutorial++;
		if(m_CurrentTutorial >= (int)m_Tutorials.size())				
		{
			m_State = STATE_DELAY_END;
			m_CounterToNextState = 0.01f;
		}
		else
		{
			TutorialData* pTutorialData =  m_Tutorials[m_CurrentTutorial];
			if(pTutorialData->m_ActivateLevel == MATLevelManager::Instance().GetCurrentLevel())
			{

				for(int i =0; i < (int)pTutorialData->m_BoardStart.size(); i++)
				{
					MATTutorial::BoardInfo* pBoardInfo = pTutorialData->m_BoardStart[i];
					MATLogicBoard::Instance().SetContentAt( pBoardInfo->m_Y , pBoardInfo->m_X , pBoardInfo->m_Content );
				}
				m_CurrentStep = 0;
				m_State = STATE_NONE;
				MATGameRule::Instance().NextTurn();
				return true;
			}
			else if( pTutorialData->m_ActivateLevel < MATLevelManager::Instance().GetCurrentLevel())
			{
				// stupid way for now
				// very dirty code
				// CHIT: FIX IT
				// CHIT: TODO
				m_State = STATE_WAIING_TOACTIVATE;
				m_CurrentTutorial++;
				if(m_CurrentTutorial >= (int)m_Tutorials.size())				
				{
					m_State = STATE_DELAY_END;
					m_CounterToNextState = 0.01f;
				}
				else
				{
					pTutorialData =  m_Tutorials[m_CurrentTutorial];
					if(pTutorialData->m_ActivateLevel == MATLevelManager::Instance().GetCurrentLevel())
					{

						for(int i =0; i < (int)pTutorialData->m_BoardStart.size(); i++)
						{
							MATTutorial::BoardInfo* pBoardInfo = pTutorialData->m_BoardStart[i];
							MATLogicBoard::Instance().SetContentAt( pBoardInfo->m_Y , pBoardInfo->m_X , pBoardInfo->m_Content );
						}
						m_CurrentStep = 0;
						m_State = STATE_NONE;

						MATGameRule::Instance().NextTurn();
						return true;
					}
					
				}

			}
		}
	}
	
	//m_State = STATE_CLEARED;
	return false;
	
	
}

void		MATTutorial::StartImediately()
{
	if(m_State == STATE_START && m_StartDelay > 0.01f )
	{
		m_StartDelay = 0.01f;
	}
}

void		MATTutorial::Tick(float dt)
{
	if(m_StartDelay > 0)
	{
		m_StartDelay -= dt;
		return;
	}

	if(m_AnotherClickDelay > 0)
	{
		m_AnotherClickDelay -= dt;
	}

	switch(m_State)
	{
	case STATE_NONE:
		break;
	case STATE_WAIING_TOACTIVATE:
		break;
	case STATE_START:		
		m_State = STATE_NOFINGER;
		m_CounterToNextState = 0.6f;
		break;
	case STATE_NOFINGER:
		m_CounterToNextState -= dt;
		if(m_CounterToNextState <= 0)
		{
			m_State = STATE_FINGER_POINTSTART;
			m_CounterToNextState = 0.5f;		
			
			MATTutorial::TutorialData* pTutorialData = m_Tutorials[m_CurrentTutorial];
			MATTutorial::TutorialMove* pTutorialMove = pTutorialData->m_Moves[m_CurrentStep];
			m_CurrentX = pTutorialMove->m_StartX;
			m_CurrentY = pTutorialMove->m_StartY;
			m_PosStart = m_PosFinger = MATGame::GetBoardPos(m_CurrentY,m_CurrentX);			
			
			if(m_pUIInstruction)
				m_pUIInstruction->SetTextA(pTutorialMove->m_Text1);
			
			//m_DirToTarget = m_PosEnd - m_PosFinger;
			//m_DistToTravel = m_DirToTarget.Magnitude();			
			//m_DirToTarget.Normalize();
		}
		break;
	case STATE_FINGER_POINTSTART:
		//m_CounterToNextState -= dt;
		//if(m_CounterToNextState <= 0)
		//{
		//	m_State = STATE_MOVE;			
		//}
		break;
		/*
	case STATE_MOVE:
		{
			m_PosFinger += ( m_DirToTarget* dt );
			const math::Vec2 NewDir = m_PosFinger - m_PosStart;			
			const float Test = NewDir.Magnitude();
			GENGameState::GetGame()->GetGameMatch5()->MouseButtonDown(NULL, m_PosFinger);
			if( Test >= m_DistToTravel)
			{
				m_State = STATE_FINGER_POINTEND;
				m_PosFinger = m_PosEnd;
				m_CounterToNextState = 0.5f;
				
			}
		}
		*/

		break;
	case STATE_FINGER_POINTEND:
		{
		MATTutorial::TutorialData* pTutorialData = m_Tutorials[m_CurrentTutorial];
		MATTutorial::TutorialMove* pTutorialMove = pTutorialData->m_Moves[m_CurrentStep];
		
		m_CurrentX = pTutorialMove->m_EndX;
		m_CurrentY = pTutorialMove->m_EndY;
		m_PosEnd = MATGame::GetBoardPos(m_CurrentY,m_CurrentX);
		m_PosFinger = m_PosEnd;

		if(m_pUIInstruction)
			m_pUIInstruction->SetTextA(pTutorialMove->m_Text2);
		//m_CounterToNextState -= dt;
		//if(m_CounterToNextState <= 0)
		//	m_State = STATE_MOVEFINISH;			
		}
		break;
	case STATE_MOVEFINISH:
		{
			m_CurrentX = -1;
			m_CurrentY = -1;
			//GENGameState::GetGame()->GetGameMatch5()->MouseButtonReleased(NULL, m_PosFinger);		

			m_CurrentStep++;	
			TutorialData* pTutorialData =  m_Tutorials[m_CurrentTutorial];
			if(m_CurrentStep >= (int)pTutorialData->m_Moves.size())
			{
				g_pApp->GetRMS()->SetInt( RMS_TUTORIAL ,pTutorialData->m_ActivateLevel);
				//g_pApp->GetRMS()->Save();

				MATUIPopupAnimator* pPopup = MATUIPopupAnimatorMgr::Instance().GetPopup(MATUIPopupAnimatorMgr::POPUP_NAMES_MSGBOX);
					((MATUIMsgBox*)pPopup)->ShowExtra(2.0f, "LOC_COMP_TUTO" , 
											   MATUIMsgBox::ACTION_NONE);	

				m_CurrentTutorial++;
				if(m_CurrentTutorial >= (int)m_Tutorials.size())				
				{
					m_State = STATE_DELAY_END;
					m_CounterToNextState = 1.9f;
				}
				else
				{
					m_State = STATE_WAIING_TOACTIVATE;					
				}

				if(m_pUIInstruction)
					m_pUIInstruction->SetTextA("");
			}
			else
			{
				m_State = STATE_PAUSE_BEFORE_NEXTMOVE;
				m_CounterToNextState = 0.9f;
			}
		}
	break;
	case STATE_PAUSE_BEFORE_NEXTMOVE:	
		m_CounterToNextState -= dt;
		if(m_CounterToNextState <= 0)
			m_State = STATE_START;		
		break;
	case STATE_DELAY_END:
		m_CounterToNextState -= dt;
		if(m_CounterToNextState <= 0)
		{
		
			Clear();	
			MATAnimationManager::Instance().ForceFinish();
			m_State = STATE_CLEARED;			

			if(m_pUIInstruction)
				m_pUIInstruction->SetTextA("");
		}
		break;
	case STATE_CLEARED:
		break;
	default:
		break;
	}

	if(m_State <= STATE_NOFINGER)
		return;

	if(m_State >= STATE_MOVEFINISH)
		return;	

	m_SpriteFinger.m_Pos = m_PosFinger;

	m_CounterArrow.Tick(dt);
	if(m_CounterArrow.IsReady())
	{
		m_CounterArrow.Reset();
	}

	
	const float DIST = 0.05f;
	float Delta = m_CounterArrow.GetProgress();
	if(Delta > 0.5f)
		Delta = 1.0f - Delta;
	m_SpriteArrow.m_Pos = m_PosFinger -(math::Vec2(0,  (m_SpriteArrow.m_Size.y * 0.55f) + (DIST * Delta)  ));

}

void		MATTutorial::Render(float Scale)
{
	if(m_State <= STATE_NOFINGER)
		return;

	if(m_State >= STATE_MOVEFINISH)
		return;	

	m_SpriteFinger.m_Size = m_SpriteFingerSize * Scale;
	m_SpriteFinger.RenderRotated();		
	
	const math::Vec2 HALFSIZE = m_SpriteFinger.m_Size * 0.5f;
	m_SpriteBlack.m_Pos = m_SpriteFinger.m_Pos;
	m_SpriteBlack.m_Pos -= math::Vec2(0.5f + HALFSIZE.x ,0);
	m_SpriteBlack.m_Pos.y = 0.5f;
	m_SpriteBlack.m_Size.x = 1.0f;
	m_SpriteBlack.RenderRotated();

	m_SpriteBlack.m_Pos = m_SpriteFinger.m_Pos;
	m_SpriteBlack.m_Pos += math::Vec2(0.5f + HALFSIZE.x ,0);
	m_SpriteBlack.m_Pos.y = 0.5f;
	m_SpriteBlack.RenderRotated();

	m_SpriteBlack.m_Pos = m_SpriteFinger.m_Pos;
	m_SpriteBlack.m_Pos += math::Vec2(0 ,0.5f + HALFSIZE.y);
	m_SpriteBlack.m_Size.x = m_SpriteFinger.m_Size.x;
	m_SpriteBlack.RenderRotated();

	m_SpriteBlack.m_Pos = m_SpriteFinger.m_Pos;
	m_SpriteBlack.m_Pos -= math::Vec2(0,0.5f + HALFSIZE.y );	
	m_SpriteBlack.RenderRotated();

	m_SpriteArrow.m_Size = m_SpriteArrowSize * Scale;
	m_SpriteArrow.RenderRotated();
}

void		MATTutorial::OnAnimationFinish(enum MATAnimation::ANI_TYPE AnimationType)
{
	if(m_State == STATE_CLEARED)
		return;

	if(AnimationType == MATAnimation::ANI_TYPE_SMALLTOBIG)
	{
		// Smalls		
		//AddSmallThree();

		if(m_State == STATE_NONE)
			m_State = STATE_START;
		
	}
}

void	MATTutorial::AddSmallThree()
{
	if(m_CurrentStep < 0)
		return;

	if(m_State == STATE_CLEARED || m_State == STATE_DELAY_END)
		return;

	MATAnimation* pAni = NULL;	

	TutorialData* pTutorialData =  m_Tutorials[m_CurrentTutorial];

	if(m_CurrentStep >= (int)pTutorialData->m_Moves.size())
		return;

	MATTutorial::TutorialMove* pTutorialMove = pTutorialData->m_Moves[m_CurrentStep];

	MATGem* pGem;
	for(int i =0; i < (int)pTutorialMove->m_Smalls.size(); i++)
	{
		MATTutorial::BoardInfo* pBoardInfo = pTutorialMove->m_Smalls[i];

		pGem = MATLogicBoard::Instance().GetContentAt( pBoardInfo->m_Y, pBoardInfo->m_X);

		if(pGem == NULL || pGem->m_Type == 0)
		{
			MATLogicBoard::Instance().SetContentAt( pBoardInfo->m_Y , pBoardInfo->m_X , pBoardInfo->m_Content );
			pAni = MATAnimationManager::Instance().AddAnimation(	pBoardInfo->m_Y, 
																pBoardInfo->m_X, 
																pBoardInfo->m_Content,
																MATAnimation::ANI_TYPE_SMALLTOBIG
																);
		}
	}
	if(pAni)
		pAni->SetCallBack(this);

	
}

void		MATTutorial::ForceFinish()
{
	if(m_CurrentTutorial < (int)m_Tutorials.size())
	{
		TutorialData* pTutorialData =  m_Tutorials[m_CurrentTutorial];
		if(pTutorialData)
			g_pApp->GetRMS()->SetInt(RMS_TUTORIAL, pTutorialData->m_ActivateLevel );	
	}

	if(m_pUIInstruction)
		m_pUIInstruction->SetTextA("");

	m_State = STATE_CLEARED;
}

void		MATTutorial::MouseButtonDown(const math::Vec2& Pos, int Y, int X)
{
	if(m_AnotherClickDelay > 0)
		return;

	if( m_CurrentX == X && m_CurrentY == Y )
	{
		
		MATLogicBoard::Instance().MouseButtonDown(Pos,Y,X);
		//bool TEMP = false;
		//MATLogicBoard::Instance().MouseButtonReleased(Pos,Y,X,TEMP);
		if(m_State == STATE_FINGER_POINTSTART &&
			Y == m_CurrentY && X == m_CurrentX
			)
		{
			m_AnotherClickDelay = 0.5f;
			NextState();
			_LOG(MSG_COMMENT,"MouseButtonDown NextState");
		}
	}
}

void		MATTutorial::MouseButtonReleased(const math::Vec2& Pos, int Y, int X)
{
	if(m_AnotherClickDelay > 0)
		return;


	if( m_CurrentX == X && m_CurrentY == Y )
	{
		//m_State = STATE_FINGER_POINTEND;
		bool TEMP = false;
		MATLogicBoard::Instance().MouseButtonReleased(Pos,Y,X,TEMP);
		if(m_State == STATE_FINGER_POINTEND)
		{
			m_AnotherClickDelay = 0.5f;
			NextState();
			_LOG(MSG_COMMENT,"MouseButtonReleased NextState");
		}
	}
}

void		MATTutorial::NextState()
{
	m_State = (STATE)((int)m_State + 1);
}
